/*
 * Copyright 2010 Aekold Helbrass
 * 
 * This file is part of RosterComposer.
 * 
 * RosterComposer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * RosterComposer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with RosterComposer.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.heresylabs.rostercomposer;

import java.awt.Dimension;
import java.util.List;
import javax.swing.AbstractSpinnerModel;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import org.heresylabs.rostercomposer.roster.RosterEntry;
import org.heresylabs.rostercomposer.units.Option;

/**
 *
 * @author Aekold Helbrass <Helbrass@gmail.com>
 */
public class OptionsGroupLimited extends AbstractOptionsGroup {

    private InternalOptionSpinner[] spinners;
    private int count;

    public OptionsGroupLimited(RosterEntry rosterEntry, Option option) {
        super(rosterEntry, option);

        List<Option> options = getOption().getOptions();
        if (options == null || options.isEmpty()) {
            return;
        }

        spinners = new InternalOptionSpinner[options.size()];
        for (int i = 0; i < options.size(); i++) {
            Option o = options.get(i);
            InternalOptionSpinner spinner = new InternalOptionSpinner(o, new GroupSpinnerModel(o, rosterEntry));
            spinners[i] = spinner;
            constraints.gridy++;
            super.add(spinner, constraints);
        }
        checkEnabled();
    }

    @Override
    protected void uncheckEmptyGroup() {
        if (getOption().isFree()) {
            int numberSelected = 0;
            if (spinners != null && spinners.length > 0) {
                for (int i = 0; i < spinners.length; i++) {
                    InternalOptionSpinner spinner = spinners[i];
                    numberSelected += spinner.getCurrentValue();
                }
            }
            if (numberSelected == 0) {
                thisOptionCheck.deselect();
            }
        }
    }

    @Override
    public void select() {
        thisOptionCheck.select();
    }

    @Override
    public void deselect() {
        thisOptionCheck.deselect();
        if (spinners == null || spinners.length < 1) {
            return;
        }
        for (int i = 0; i < spinners.length; i++) {
            InternalOptionSpinner spinner = spinners[i];
            spinner.deselect();
        }
    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        if (spinners == null || spinners.length < 1) {
            return;
        }
        for (int i = 0; i < spinners.length; i++) {
            InternalOptionSpinner spinner = spinners[i];
            if (enabled) {
                spinner.setEnabled(true);
            }
            else {
                spinner.deselect();
                spinner.setEnabled(false);
            }
        }
    }

    private int getMaxNumber() {
        if (getOption().isAnyModels()) {
            return getRosterEntry().getNumber();
        }
        if (getOption().isRepeatable()) {
            int req = getOption().getRequireNumber();
            return getRosterEntry().getNumber() / req;
        }
        return getOption().getMaxNumber();
    }

    private class GroupSpinnerModel extends AbstractSpinnerModel {

        private final Option option;
        private final RosterEntry rosterEntry;

        public GroupSpinnerModel(Option option, RosterEntry rosterEntry) {
            this.option = option;
            this.rosterEntry = rosterEntry;
        }

        private int getCurrentValue() {
            return rosterEntry.getOptionsCount(option);
        }

        @Override
        public Object getValue() {
            return getCurrentValue();
        }

        @Override
        public void setValue(Object value) {
            int val = ((Integer) value).intValue();
            int currentValue = getCurrentValue();

            if (val == currentValue) {
                return;
            }

            if (val > currentValue) {
                int diff = val - currentValue;
                count += diff;
            }
            else {
                int diff = currentValue - val;
                count -= diff;
            }

            rosterEntry.setOptionsCount(option, val);
            fireStateChanged();
            if (count == 0) {
                thisOptionCheck.deselect();
            }
            else {
                thisOptionCheck.select();
            }
        }

        @Override
        public Object getNextValue() {
            int maxNumber = getMaxNumber();
            if (maxNumber == 0 || maxNumber == count) {
                return null;
            }
            return getCurrentValue() + 1;
        }

        @Override
        public Object getPreviousValue() {
            if (getCurrentValue() == 0) {
                return null;
            }
            return getCurrentValue() - 1;
        }

    }

    private class InternalOptionSpinner extends JPanel {

        private final Option option;
        private final JSpinner spinner;
        private final GroupSpinnerModel spinnerModel;

        public InternalOptionSpinner(Option option, GroupSpinnerModel spinnerModel) {
            this.option = option;
            this.spinnerModel = spinnerModel;
            setLayout(new BoxLayout(this, BoxLayout.X_AXIS));

            spinner = new JSpinner(spinnerModel);

            Dimension size = new Dimension(50, spinner.getMinimumSize().height);
            spinner.setPreferredSize(size);
            spinner.setMaximumSize(size);
            spinner.setMinimumSize(size);

            super.add(spinner);
            super.add(Box.createHorizontalStrut(6));
            super.add(new JLabel(option.toString()));
            super.add(Box.createHorizontalGlue());
        }

        @Override
        public void setEnabled(boolean enabled) {
            super.setEnabled(enabled);
            spinner.setEnabled(enabled);
        }

        private int getCurrentValue() {
            return spinnerModel.getCurrentValue();
        }

        private void deselect() {
            spinnerModel.setValue(0);
        }

    }

}
